var lineReader = require('line-reader');
var fs = require('fs');
var _ = require("underscore");
var vm = require('vm');
var split = require("hy5b/t").split;

var moment = require('moment');

var path = require('path');
var mkdirp = require('mkdirp');

function _createFile(sfilePath) {
  var dir_name = path.dirname(sfilePath);
  // origin file path
  var ori_path = path.resolve(sfilePath);
  // folder path
  var dir_path = path.resolve(dir_name);

  mkdirp.sync(dir_path);

  return fs.createWriteStream(ori_path);
}

function _fileParse(sfileName, fcall) {
  if (path.extname(sfileName) === '.js') {
    var obj = require(sfileName);
    console.log('conf:', sfileName)
    fcall(obj);
  }
  var str = "";
  var array = [];
  var bmultiConfig = false;
  lineReader.eachLine(sfileName, function(line) {
    //一行是一组配置
    try {
      var obj = JSON.parse(line);
      array.push(obj);
    } catch (e) {
      return false;
    }
  }).then(function() {
    //整个文件是一组配置
    if (array.length != 0) {
      fcall(array);
    } else {

      try {
        var obj = require(sfileName);
        fcall(obj);
      } catch (e) {
      	console.error(e)
      }
    }
  })
}

var util = {};
util.startsWith = function (sequence, head) {

  sequence = '' + sequence;
  return sequence.slice(0, head.length) === head;
};

util.endsWith = function (sequence, tail) {

  sequence = '' + sequence;
  return sequence.slice(-tail.length) === tail;
};

util.trim = function (sequence) {

  sequence = '' + sequence;
  return sequence.replace(/^\s*|\s*$/g, '');
};

function _generateFromTemplet(stempletFile, sconfigFile, oscope, sdistPath, sdistRoot, cb) {
  var _sjavascript = "";
  var _bcodeStart = false;
  var _bcode = false;

  oscope.cf = path.basename(sconfigFile, path.extname(sconfigFile));//delete suffix

  var distFileName = "";
  if (oscope.of != undefined) {
    distFileName = oscope.of;
  } else {
    if (oscope.pref != undefined) {
      distFileName = oscope.pref;
    } else {
      distFileName = oscope.cf;
    }

    distFileName += path.basename(stempletFile);

    distFileName = oscope.rename != undefined
      && oscope.rename[path.basename(stempletFile)] != undefined
      ? oscope.rename[path.basename(stempletFile)]
      : distFileName;
  }

  var sdistFolder = "";
  if (oscope.distPref != undefined) {
    sdistFolder = path.resolve(sdistRoot, oscope.distPref, sdistPath);
  } else {
  	if (oscope.pathRename) {
  		let renamedDistPath = sdistPath
  		for (var renamePath in oscope.pathRename) {
  			renamedDistPath = renamedDistPath.replace(renamePath, oscope.pathRename[renamePath])
  		}
  		console.log('sdistRoot:', sdistRoot, 'renamedDistPath:', renamedDistPath)
  		sdistFolder = path.resolve(sdistRoot, renamedDistPath);
  	} else {
  		console.log('sdistRoot:', sdistRoot, 'sdistPath:', sdistPath)
    	sdistFolder = path.resolve(sdistRoot, sdistPath);
  	}
  }
  
  var _of = _createFile(path.resolve(sdistFolder, distFileName));

  oscope.echo = function(str) {
    _of.write("" + str);
  };

  stempletFile = path.resolve(stempletFile);
  var virtEnv = {
    source: fs.readFileSync(stempletFile, 'utf8'),
    code: '',
    global: oscope
  };

  var parts = [];

  split(virtEnv.source, /[\r\n]{0,1} *```js/, /```[\r\n]{0,1}/, function(a, b) {
    if (a != null) {
      split(a, "{{", "}}", function(a1, b1) {
        if (a1 != null) {
          parts.push({
            content: a1
          });
        }
        
        if (b1 != null) {
          parts.push({
            type: "=",
            content: b1
          });
        }
      });
    }
    
    if (b != null) {
      parts.push({
        type: "js",
        content: b
      });
    }
  });

  var blocks = [];
  var blockIdx = -1;
  var blocksId = '__blocks';

  var code = _.map(parts, function (part) {
    if (part.type === "js") {
      return util.trim(part.content);
    } else if (part.type === "=") {
      return "echo(" + part.content + ");";
    } else {
      blockIdx += 1;
      blocks[blockIdx] = part.content;
      return 'echo(' + blocksId + '[' + blockIdx + ']);';
    }
  }).join(" ");

  virtEnv.code = code;

  virtEnv.global[blocksId] = blocks;

  _.extend(virtEnv.global, {
    require: function (id) {

      if (util.startsWith(id, './') || util.startsWith(id, '../')) {
        id = path.resolve(__dirname, id);
      }
      return module.require(id);
    },
    env: process.env,
    time: moment().format(),
    author: 'water7melon'
  });

  vm.runInNewContext(virtEnv.code, virtEnv.global);
}

function templet2code(stempletFile, sconfigFile, sdistPath, sdistRoot) {
  _fileParse(sconfigFile, function(val) {
    if (_.isArray(val)) {
      for (var i = 0; i < val.length; i++) {
        if (!_.isObject(val[i])) {
          _generateFromTemplet(stempletFile, sconfigFile, {$$: val[i], pref:val[i]}, sdistPath, sdistRoot);
        } else {
          _generateFromTemplet(stempletFile, sconfigFile, val[i], sdistPath, sdistRoot);
        }
      }
    } else {
      _generateFromTemplet(stempletFile, sconfigFile, val, sdistPath, sdistRoot);
    }
  })
}

function templets2code(stemplet, sconfigFile, sdistPath, sdistRoot) {
  var stat = fs.stat(stemplet, function(err, stat) {
    if (err) {
      throw err;
    }
    
    if (stat.isDirectory()) {
      var stempletPath = stemplet;
      fs.readdir(stempletPath, function(err, files) {
        for (var i = 0; i < files.length; i++) {
          var file = files[i];
          templets2code(path.resolve(stempletPath, file), sconfigFile, sdistPath + "/" + path.basename(stempletPath), sdistRoot);
        }
      });
    } else if (stat.isFile()) {
      var stempletFile = stemplet;
      templet2code(stempletFile, sconfigFile, sdistPath, sdistRoot);
    }
  });
}

function templets2codeFrom(stemplet, sconfig, sdistRoot) {
  fs.stat(sconfig, function(err, stat) {
    if (err) {
      throw err;
    }

    if (stat.isDirectory()) { //配置文件是文件夾
      var sconfigPath = sconfig;
      fs.readdir(sconfigPath, function(err, files) {
        for (var i = 0; i < files.length; i++) {
          var file = files[i];
          templets2codeFrom(stemplet, path.resolve(sconfigPath, file), sdistRoot);
        }
      });
    } else if (stat.isFile()) {
      var sconfigFile = sconfig;
      //templets2code(stemplet, sconfigFile, ".", sdistRoot);
      //cycle one time to get rid of the outside folder name
      fs.stat(stemplet, function(err, stat2) {
        if (err) {
          throw err;
        }
        
        if (stat2.isDirectory()) {
          var stempletPath = stemplet;
          fs.readdir(stempletPath, function(err, files) {
            for (var i = 0; i < files.length; i++) {
              var file = files[i];
              templets2code(path.resolve(stempletPath, file), sconfigFile, ".", sdistRoot);
            }
          });
        } else if (stat2.isFile()) {
          var stempletFile = stemplet;
          templet2code(stempletFile, sconfigFile, ".", sdistRoot);
        }
      });
    }
  })
}

var argvs = process.argv;

if (argvs.length < 5) {
  console.log("Usage: " + path.basename(argvs[0]) + " " + path.basename(argvs[1]) + " {templet file or path} {config file or path} {dist path}");
} else {
  templets2codeFrom(argvs[2], argvs[3], argvs[4]);
}
